...loading
2024-11-30
이번에는 DB를 연동해보려고 합니다. 사실 개인 블로그이기 때문에 꼭 DB 연동까지 구현할 필요는 없다고 생각합니다.. 그래도 NextJs에서 DB를 한번 연동해보고 싶다는 욕심에 구현해봤습니다. DB는 사용 경험이 있고 nodeJS와 잘맞는 MongoDB를 사용했습니다.
초기 세팅은 어렵지 않습니다. mongoDB Atlas에서 프로젝트를 하나 생성해주고 클러스터를 생성해줍니다. 그리고 클러스터에 접근 가능한 user와 password를 설정한 후, URI를 발급 받습니다. 이제 프로젝트에서 mongodb 패키지를 설치해줍니다.
npm install mongodb
패키지가 설치되면 디비를 연동할 준비가 완료 되었습니다. 보안을 위해 루트경로에 .env.local 파일을 생성해주고 환경변수를 입력해줍니다
// .env.local DB_URI= ***** DB_NAME= *****
이제 본격적으로 연동을 시작해봅니다. 저는 클라이언트 객체를 생성해주기 위해 utils 폴더에 db.ts파일을 만들었습니다. 아래의 코드처럼 클라이언트를 생성하는 함수를 하나 만들어 두었습니다. 해당 폴더에는 db와 관련한 함수들을 모아둘 예정입니다.
// utils/db.ts import { MongoClient } from "mongodb"; export async function connectDatabase() { const client = MongoClient.connect(process.env.DB_URI as string); return client; }
지금부터가 이번 포스팅의 꽃입니다. 이번 프로젝트에서는 추가 서버를 구축해서 연동하는게 아니라, NextJS 내부에서 서버의 기능을 구현하고 싶었습니다. 따라서 API routes를 사용해봅니다. 루트 경로에 pages/api의 경로를 만들어 줍니다. 이제 그 하위에 있는 경로들은 모두 api endpoint로 사용할 수 있게 되었습니다. DB연동 테스트를 위해 test 파일을 만듭니다.
// pages/api/test.ts import type { NextApiRequest, NextApiResponse } from "next"; import { connectDatabase } from "@/utils/db"; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { let client; try { client = await connectDatabase(); if (req.method === "GET") { const db = client.db("taki-town"); const collection = db.collection("posts"); const data = await collection.findOne({ title: "test" }); if (data) { res.status(200).json(data); } else { res.status(404).json({ message: "Document not found" }); } } else { res.setHeader("Allow", ["GET"]); res.status(405).end(`Method ${req.method} Not Allowed`); } } catch (error) { console.error("Error fetching data:", error); res.status(500).json({ message: "Internal Server Error" }); } finally { if (client) { client.close(); } } }
대충.. 클라이언트에서 해당 경로로 GET 요청이 들어온다면, 아까 작성해준 DB함수를 통해 클라이언트 객체를 생성하고 title이 test인 데이터를 DB로부터 불러와 응답하는 핸들러입니다.
이제 클라이언트측 코드에서 해당 endpoint로 요청을 날리고 성공적으로 데이터를 받아오는지 확인하면 됩니다. 테스트를 위해 메인페이지에서 요청을 날려봅니다.
// page.tsx "use client"; import { useEffect } from "react"; import styles from "./page.module.css"; export default function Home() { useEffect(() => { const fetchData = async () => { try { const response = await fetch("/api/test"); if (!response.ok) { throw new Error("Failed to fetch data"); } const result = await response.json(); console.log(result); } catch (error) { console.error("Error fetching data:", error); } }; fetchData(); }, []); return ( <main className={styles.main}> </main> ); }
그리고 개발자도구를 열어 클라이언트 측에 데이터가 성공적으로 응답되는지 확인합니다.
성공했습니다..!
이상으로 디비를 연동하는 과정을 포스팅해봤습니다. 아쉬웠던 점은 API routes를 제대로 이해하면서 구현하지는 못하지 않았나 생각이 듭니다. 특히 API routes는 서버리스 함수로 구성되는데 이번 프로젝트가 서버리스 함수로 구성하기에 적합한 프로젝트였는지 등을 사전에 고민해봤으면 더 좋았을 것 같습니다. 사실.. 가벼운 프로젝트이기에 크게 문제가 없고 오히려 서버리스 함수를 도입하는 것이 적합하다고 생각합니다. 하지만 지금이라도 알게 되었으니 나중에는 프로젝트를 준비할 때 이러한 지식을 잘 활용해봐야겠습니다
Comments